using System;
using System.Collections.Generic;
using System.Text;

namespace COME342.CollisionResolution.BinaryTree
{
    /// <summary>
    /// Computed Chaining.
    /// Kerem KAT
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ComputedChaining<T> where T : ILischPseudoLinkRow
    {
        int size;
        bool isTableFull = false;

        public bool IsTableFull { get { return isTableFull; } }

        List<LischTableEntry<T>> tbl;

        public List<LischTableEntry<T>>.Enumerator GetEnumerator() { return tbl.GetEnumerator(); }

        public LischTableEntry<T> this[int index]
        {
            get { return tbl[index % size]; }
        }

        public ComputedChaining(int mod)
        {
            size = mod;
            tbl = new List<LischTableEntry<T>>(size);
            for (int i = 0; i < size; ++i)
            {
                tbl.Add(default(LischTableEntry<T>));
            }
        }

        public bool IsColliding(T row)
        {
            return tbl[row.GetId() % size] != null && tbl[row.GetId() % size].data.GetId() != -1;
        }

        private int Probe(LischTableEntry<T> ihte)
        {
            if (ihte == null)
                return -1;
            return ihte.data.GetPseudoLink() * (ihte.data.GetId() / size % size);
        }

        public int Insert(T row)
        {
            int h = row.GetId() % size;
            if (tbl[h] == null || tbl[h].data.GetId() == -1)//home address empty
                tbl[h] = new LischTableEntry<T>(row);

            if (tbl[h].data.GetId() != row.GetId()) // move entry
            {
                while (tbl[h].data.GetPseudoLink() != -1)
                {
                    h += Probe(tbl[h]);
                }
                
                int i = 1;
                int j = Probe(tbl[i]);                
                
                while (tbl[j] != null)
                {
                    i++;
                    if (i > size)
                    {
                        isTableFull = true;
                        return -1;
                    }
                    j = Probe(tbl[i]);
                }

                tbl[h].data.SetPseudoLink(i);                
                tbl[j] = new LischTableEntry<T>(row);
            }

            return -1;

        }


    }
}
